import numpy as np
import line_search


def wolfe_line_search(f, g, x0, d, f0, g0):
    return line_search.wolfe(f, g, x0, d, f0, g0, 0.25, 0.75, 1.0, 10000.0, 100)


def step(f, g, x, d, fk, gk):
    """
    Perform line search

    :param f: objective function
    :param g: gradient
    :param x: starting point
    :param d: direction
    :param fk: f(x0)
    :param gk: g(x0)
    :return: (x_{k+1}, f_{k+1}, iterations)
    """
    if (gk @ d) > 0:
        d = -d
    a, ls_it = wolfe_line_search(f, g, x, d, fk, gk)
    x_new = x + a * d
    f_new = f(x_new)
    return x_new, f_new, ls_it


def is_stopping(x, fk, gk, eps):
    """
    Check if stopping criterion is met

    :param x: point
    :param fk: function value
    :param gk: gradient value
    :param eps: precision
    :return:
    """
    return np.sqrt(np.dot(gk, gk)) < eps * max(1, np.sqrt(np.dot(x, x)).item())
